package com.atom.module.document.ui;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Point;
import android.media.Image;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

import com.atom.module.document.Document;
import com.atom.module.document.R;
import com.atom.module.document.helper.BitmapHelper;
import com.atom.module.document.helper.DocumentHelper;
import com.atom.module.document.utils.DataSmoothingUtils;
import com.atom.module.document.utils.YUV420Utils;
import com.atom.module.logger.Logger;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.RequestOptions;
import com.otaliastudios.cameraview.CameraException;
import com.otaliastudios.cameraview.CameraListener;
import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.PictureResult;
import com.otaliastudios.cameraview.controls.Engine;
import com.otaliastudios.cameraview.controls.Facing;
import com.otaliastudios.cameraview.controls.Flash;
import com.otaliastudios.cameraview.controls.PictureFormat;
import com.otaliastudios.cameraview.filter.Filter;
import com.otaliastudios.cameraview.filter.Filters;
import com.otaliastudios.cameraview.frame.Frame;
import com.otaliastudios.cameraview.frame.FrameProcessor;
import com.otaliastudios.cameraview.size.Size;
import com.otaliastudios.cameraview.size.SizeSelector;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.internal.observers.BlockingBaseObserver;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;

/**
 * All rights Reserved, Designed By www.rongdasoft.com
 *
 * @version V1.0
 * @Title: DocumentCameraActivity
 * @Description:
 * @author: wuyongzheng
 * @date: 2022/3/23
 * @Copyright: 2022/3/23 www.rongdasoft.com Inc. All rights reserved.
 */
public class CameraViewActivity extends AbstractAppCompatActivity {

    private boolean isSingle = false;
    private int startResultCode = -1;
    private String defaultDocumentSourceFilePath;

    private CompositeDisposable mCompositeDisposable;

    public LinkedList<Point> leftTop = new LinkedList<>();
    public LinkedList<Point> rightTop = new LinkedList<>();
    public LinkedList<Point> rightBottom = new LinkedList<>();
    public LinkedList<Point> leftBottom = new LinkedList<>();
    public int defaultSize = 10;

    private volatile boolean isPause = false;

    public Point createPoint(LinkedList<Point> pointsLinked) {
        int[] xArray = new int[pointsLinked.size()];
        int[] yArray = new int[pointsLinked.size()];
        for (int i = 0; i < pointsLinked.size(); i++) {
            Point point = pointsLinked.get(i);
            xArray[i] = point.x;
            yArray[i] = point.y;
        }
        int[] result = new int[pointsLinked.size()];
        DataSmoothingUtils.cubicSmooth5(xArray, result, defaultSize);
        int resultX = result[4];
        DataSmoothingUtils.cubicSmooth5(yArray, result, defaultSize);
        int resultY = result[4];
        return new Point(resultX, resultY);
    }

    private void initParams(@Nullable Bundle savedInstanceState) {
        Intent intent = getIntent();
        if (intent == null) {
            finish();
            return;
        }
        defaultDocumentSourceFilePath = DocumentHelper.getDocumentSourcePath(this, null);
        startResultCode = intent.getIntExtra(DocumentHelper.camera_result_code_param, -1);
        isSingle = intent.getBooleanExtra(DocumentHelper.camera_model_param, false);
        if (startResultCode == -1 && intent.getBooleanExtra(DocumentHelper.document_check_history_param, true)) {
            new Handler(Looper.getMainLooper()).post(this::checkHistory);
        }
    }

    private byte[] getDataFromFrame(Frame frame) {
        if (frame.getDataClass() == byte[].class) {
            return frame.getData();
            // Process byte array...
        } else if (frame.getDataClass() == Image.class) {
            // Process android.media.Image...
            try {
                return YUV420Utils.imageToYUV420(frame.getData());
            } catch (Exception e) {
                Logger.e(e);
            }
        }
        return null;
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Logger.e("onCreate");
        initParams(savedInstanceState);
        setContentView(R.layout.activity_camera_view);
        CameraView camera = findViewById(R.id.camera_view);
        camera.setExperimental(true);
        camera.setEngine(Engine.CAMERA2);
        camera.setLifecycleOwner(this);
        Filter filter = Filters.BLACK_AND_WHITE.newInstance();
        camera.setFilter(filter);
        camera.setPictureFormat(PictureFormat.JPEG);
        camera.setFrameProcessingFormat(ImageFormat.YUV_420_888);
        camera.addFrameProcessor(new FrameProcessor() {
            @Override
            public void process(@NonNull Frame frame) {
                byte[] dataFromFrame = getDataFromFrame(frame);
                Logger.e("frame %s %s %s %s ", frame.getTime(), frame.getFormat(), frame.getSize(), dataFromFrame.length);
            }
        });
        camera.addCameraListener(new CameraListener() {
            @Override
            public void onCameraError(@NonNull CameraException exception) {
                super.onCameraError(exception);
                Logger.e(exception);
            }

            @Override
            public void onPictureTaken(@NonNull PictureResult result) {
                super.onPictureTaken(result);
                Observable.just(result.getData())
                    .flatMap((Function<byte[], ObservableSource<File>>) bytes -> {
                        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                        bitmap = BitmapHelper.rotateBitmap(bitmap, result.getRotation(), true);
                        if (result.getFacing() == Facing.FRONT) {
                            bitmap = BitmapHelper.convertBmp(bitmap, true);
                        }
                        File saveFile = DocumentHelper.createFile(DocumentHelper.createFileByUUID(defaultDocumentSourceFilePath), true);
                        try {
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(saveFile));
                        } catch (Exception e) {
                            Logger.e(e);
                        }
                        return observer -> observer.onNext(saveFile);
                    }).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new BlockingBaseObserver<File>() {
                        @Override
                        public void onNext(File file) {
                            toggleBottomButtons(false);
                            if (isSingle) {
                                Intent result = new Intent();
                                // TODO 跳转到单个处理界面
                                if (startResultCode > 0) {
                                    result.setData(Uri.fromFile(file));
                                    setResult(startResultCode, result);
                                    finish();
                                    return;
                                }
                                result.setClass(CameraViewActivity.this, SingleHandleActivity.class);
                                result.putExtras(getIntent());
                                result.putExtra(DocumentHelper.camera_result_value_param, file.getAbsolutePath());
                                startActivity(result);
                                finish();
                            } else {
                                // 更新布局
                                Document.addDocument(file.getAbsolutePath(), Document.getCurrentFilter());
                                toggleMoreType();
                            }
                        }

                        @Override
                        public void onError(Throwable e) {
                            toggleBottomButtons(false);
                        }
                    });
            }

        });
        camera.setPictureSize(new SizeSelector() {
            @NonNull
            @Override
            public List<Size> select(@NonNull List<Size> source) {
                double targetRatio = (double) 3 / 4;//预览标准比值
                double aspectTolerance = 0.1;//预览标准比值
                double minDiff = Double.MAX_VALUE;
                int targetHeight = 2592;
                int targetWidth = 1944;
                Size optimalSize = null;
                Logger.e("list %s", source);
                // Try to find an size match aspect ratio and size
                for (Size size : source) {
                    double ratio = size.getWidth() / (float) size.getHeight();
                    if (Math.abs(ratio - targetRatio) > aspectTolerance) {
                        continue;
                    }
                    int diff = Math.abs(size.getWidth() - targetWidth) + Math.abs(size.getHeight() - targetHeight);
                    if (diff < minDiff) {
                        optimalSize = size;
                        minDiff = diff;
                    }
                }

                // Cannot find the one match the aspect ratio, ignore the requirement
                if (optimalSize == null) {
                    minDiff = Double.MAX_VALUE;
                    for (Size size : source) {
                        int diff = Math.abs(size.getHeight() - targetHeight) + Math.abs(size.getWidth() - targetWidth);
                        if (diff < minDiff) {
                            optimalSize = size;
                            minDiff = diff;
                        }
                    }
                }
                Logger.e("result %s", optimalSize);
                return Collections.singletonList(optimalSize);
            }
        });
        camera.setPreviewStreamSize(new SizeSelector() {
            @NonNull
            @Override
            public List<Size> select(@NonNull List<Size> source) {
                double targetRatio = (double) 3 / 4;//预览标准比值
                double aspectTolerance = 0.1;//预览标准比值
                double minDiff = Double.MAX_VALUE;
                int targetHeight = 2592;
                int targetWidth = 1944;
                Size optimalSize = null;
                Logger.e("setPreviewStreamSize list %s", source);
                // Try to find an size match aspect ratio and size
                for (Size size : source) {
                    double ratio = size.getWidth() / (float) size.getHeight();
                    if (Math.abs(ratio - targetRatio) > aspectTolerance) {
                        continue;
                    }
                    int diff = Math.abs(size.getWidth() - targetWidth) + Math.abs(size.getHeight() - targetHeight);
                    if (diff < minDiff) {
                        optimalSize = size;
                        minDiff = diff;
                    }
                }
                // Cannot find the one match the aspect ratio, ignore the requirement
                if (optimalSize == null) {
                    minDiff = Double.MAX_VALUE;
                    for (Size size : source) {
                        int diff = Math.abs(size.getHeight() - targetHeight) + Math.abs(size.getWidth() - targetWidth);
                        if (diff < minDiff) {
                            optimalSize = size;
                            minDiff = diff;
                        }
                    }
                }
                Logger.e("setPreviewStreamSize result %s", optimalSize);
                return Collections.singletonList(optimalSize);
            }
        });
        camera.addCameraListener(new CameraListener() {
            @Override
            public void onCameraOpened(@NonNull CameraOptions options) {
                super.onCameraOpened(options);
                toggleCamera(camera.getFlash());
            }

            @Override
            public void onCameraClosed() {
                super.onCameraClosed();
            }
        });
        view(R.id.closeCamera, view -> {
            view.setOnClickListener(v -> onBackPressed());
        });
        view(R.id.sharedCamera, view -> {
            view.setOnClickListener(v -> {
                Toast.makeText(this, "分享一下", Toast.LENGTH_SHORT).show();
                Logger.e(" w = %s , h =%s  , %s", camera.getWidth(), camera.getHeight() ,camera.getEngine());
            });
        });
        view(R.id.gridLine, view -> {
            view.setOnClickListener(v -> {
                Toast.makeText(this, "网格线", Toast.LENGTH_SHORT).show();
                View viewById = findViewById(R.id.gridLineView);
                viewById.setVisibility(viewById.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
            });
        });
        view(R.id.flashSwitch, (PickView<TextView>) view -> {
            view.setOnClickListener(v -> {
                Flash flash = camera.getFlash();
                switch (flash) {
                    case OFF: {
                        camera.setFlash(Flash.ON);
                        view.setText("单拍");
                        break;
                    }
                    case ON: {
                        camera.setFlash(Flash.AUTO);
                        view.setText("自动");
                        break;
                    }
                    case AUTO: {
                        camera.setFlash(Flash.TORCH);
                        view.setText("开");
                        break;
                    }
                    case TORCH: {
                        camera.setFlash(Flash.OFF);
                        view.setText("关");
                        break;
                    }
                }
            });
        });
        view(R.id.shutterCamera, view -> {
            view.setOnClickListener(v -> {
                if (camera.isOpened()) {
                    toggleBottomButtons(true);
                    //camera.takePicture();
                    camera.takePictureSnapshot();
                }
            });
        });
        view(R.id.autoDocument, view -> {
            view.setOnClickListener(v -> {

            });
        });
        view(R.id.toggleFrontBackCamera, view -> {
            view.setOnClickListener(v -> {
                Facing facing = camera.getFacing();
                camera.setFacing(facing == Facing.BACK ? Facing.FRONT : Facing.BACK);
            });
        });
        view(R.id.continuousShooting, (PickView<ImageView>) view -> {
            view.setOnClickListener(v -> {
                // 设置单拍和多拍模式
                if (camera.isOpened()) {
                    isSingle = !isSingle;
                    toggleMoreType();
                }
            });
        });
        view(R.id.backMoreType, v -> v.setOnClickListener(v12 -> onBackPressed()));
        view(R.id.moreSaveList, view -> {
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (Document.isEmptyDocument()) return;
                    Document.addDocument(Document.sizeDocument(), Document.Entry.EMPTY);
                    Intent result = new Intent(CameraViewActivity.this, MoreHandleActivity.class);
                    result.putExtras(getIntent());
                    startActivityForResult(result, 2048);
                }
            });
        });
        view(R.id.switchFilter, view -> view.setOnClickListener(v -> view(R.id.filterLayout, filterLayout -> {
            filterLayout.setVisibility(filterLayout.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
            toggleFilter(filterLayout);
        })));
        view(R.id.filterEmpty, filterEmpty -> filterEmpty.setOnClickListener(v -> {
            Document.setCurrentFilter(Document.FilterWrapper.filter_empty_wrapper);
            view(R.id.filterLayout, filterLayout -> {
                toggleFilter(filterLayout);
                filterLayout.setVisibility(View.GONE);
            });
        }));
        view(R.id.filterSharp, filterEmpty -> filterEmpty.setOnClickListener(v -> {
            Document.setCurrentFilter(Document.FilterWrapper.filter_sharp_wrapper);
            view(R.id.filterLayout, filterLayout -> {
                toggleFilter(filterLayout);
                filterLayout.setVisibility(View.GONE);
            });
        }));
    }

    private void toggleCamera(Flash flash) {
        view(R.id.flashSwitch, (PickView<TextView>) view -> {
            switch (flash) {
                case OFF: {
                    view.setText("单拍");
                    break;
                }
                case ON: {

                    view.setText("自动");
                    break;
                }
                case AUTO: {
                    view.setText("开");
                    break;
                }
                case TORCH: {
                    view.setText("关");
                    break;
                }
            }
        });
    }

    private void toggleShootingModel(boolean isSingleModel) {
        view(R.id.showShutterModel, (PickView<TextView>) v1 -> {
            v1.setText(isSingleModel ? "单拍模式" : "连拍模式");
        });
        view(R.id.continuousShooting, (PickView<ImageView>) view -> {
            view.setBackgroundColor(isSingleModel ? Color.RED : Color.GREEN);
        });
        toggleMoreType();
    }

    private void toggleBottomButtons(Boolean hide) {
        runOnUiThread(() -> {
            float alpha = hide ? 0f : 1f;
            view(R.id.shutterCamera, view -> {
                view.animate().alpha(alpha).start();
                view.setClickable(!hide);
            });

            view(R.id.skipDocument, view -> {
                view.animate().alpha(alpha).start();
                view.setClickable(!hide);
            });

            view(R.id.continuousShooting, view -> {
                view.animate().alpha(alpha).start();
                view.setClickable(!hide);
            });
        });
    }

    private void toggleMoreType() {
        if (isSingle) {
            view(R.id.defaultType, view -> {
                view.setVisibility(View.VISIBLE);
            });
            view(R.id.moreType, view -> {
                view.setVisibility(View.GONE);
            });
            view(R.id.switchFilter, view -> {
                view.setVisibility(View.GONE);
            });
        } else {
            view(R.id.defaultType, view -> {
                view.setVisibility(Document.isEmptyDocument() ? View.VISIBLE : View.GONE);
            });
            view(R.id.moreType, view -> {
                view.setVisibility(!Document.isEmptyDocument() ? View.VISIBLE : View.GONE);
            });
            view(R.id.switchFilter, view -> {
                view.setVisibility(View.VISIBLE);
            });
            if (!Document.isEmptyDocument()) {
                Document.Entry entry = Document.lastDocument();
                String s = entry.getSourcePath();
                if (!isDestroyed()) {
                    RequestOptions options = new RequestOptions()
                        .centerCrop()
                        .diskCacheStrategy(DiskCacheStrategy.NONE);
                    view(R.id.moreSaveList, (PickView<ImageView>) view -> {
                        Glide.with(this)
                            .load(s)
                            .apply(options)
                            .transition(DrawableTransitionOptions.withCrossFade())
                            .into(view);
                    });
                }
                view(R.id.moreSize, (PickView<TextView>) v -> v.setText(String.valueOf(Document.sizeDocument())));
            }
        }
    }

    private void toggleFilter(View filterLayout) {
        if (!isSingle) {
            if (filterLayout.getVisibility() == View.VISIBLE) {
                view(R.id.filterEmptyShow, (PickView<ImageView>) image -> {
                    image.setBackground(null);
                });
                view(R.id.filterSharpShow, (PickView<ImageView>) image -> {
                    image.setBackground(null);
                });
                Document.FilterWrapper currentFilter = Document.getCurrentFilter();
                switch (currentFilter) {
                    case filter_sharp_wrapper: {
                        view(R.id.filterSharpShow, (PickView<ImageView>) image -> {
                            image.setBackgroundResource(R.drawable.bg_blue);
                        });
                        break;
                    }
                    default: {
                        view(R.id.filterEmptyShow, (PickView<ImageView>) image -> {
                            image.setBackgroundResource(R.drawable.bg_blue);
                        });
                    }
                }
            }
        }
    }

    private void checkHistory() {
        // 检查本地历史是否存在上次
        String documentSourcePath = DocumentHelper.getDocumentSourcePath(this, null);
        File sourceFolder = new File(documentSourcePath);
        List<Document.Entry> history = new ArrayList<>();
        File[] files = sourceFolder.listFiles();
        if (files == null || files.length == 0) return;
        for (File file : files) {
            history.add(Document.Entry.defaultEntry(file.getAbsolutePath()));
        }
        if (history.size() > 0) {
            // 存在历史的 dialog 弹窗
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("历史回溯");
            builder.setMessage("存在上次未执行的文件是否继续上次");
            builder.setCancelable(false);
            builder.setPositiveButton("sure", (dialog, which) -> {
                Document.addAllDocument(history);
                isSingle = false;
                toggleMoreType();
            });
            builder.setNegativeButton("cancel", (dialog, which) -> {
                for (Document.Entry entry : history) {
                    DocumentHelper.deleteFile(entry.getSourcePath());
                }
                history.clear();
            });
            AlertDialog dialog = builder.create();
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();
        }
    }

    @Override
    public void onBackPressed() {
        if (isSingle) {
            super.onBackPressed();
            return;
        }
        if (Document.isEmptyDocument()) {
            super.onBackPressed();
            return;
        }
        DocumentHelper.documentDeleteShow(CameraViewActivity.this, new BlockingBaseObserver<Boolean>() {
            @Override
            public void onNext(Boolean aBoolean) {
                if (aBoolean) {
                    // 删除照片
                    for (Document.Entry entry : Document.getDocument()) {
                        if (TextUtils.isEmpty(entry.getSourcePath())) continue;
                        boolean b = DocumentHelper.deleteFile(entry.getSourcePath());
                        Logger.e("删除 %s ", b);
                    }
                    Document.clearDocument();
                    toggleMoreType();
                }
            }

            @Override
            public void onError(Throwable e) {
                // 结束自己
                finish();
            }
        });
    }

    @Override
    protected void onResume() {
        Logger.e("onResume");
        super.onResume();
        toggleBottomButtons(false);
        toggleShootingModel(isSingle);
        toggleMoreType();
        isPause = false;
    }

    @Override
    protected void onPause() {
        isPause = true;
        Logger.e("onPause");
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        Logger.e("onDestroy");
        if (this.mCompositeDisposable != null) {
            this.mCompositeDisposable.clear();
            this.mCompositeDisposable = null;
        }
        super.onDestroy();
    }

    @Override
    public void finish() {
        Logger.e("finish");
        super.finish();
    }

    private void addSubscribe(Disposable disposable) {
        if (this.mCompositeDisposable == null) {
            this.mCompositeDisposable = new CompositeDisposable();
        }
        this.mCompositeDisposable.add(disposable);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_FIRST_USER) {
            Intent intent = new Intent(CameraViewActivity.this, DocumentListActivity.class);
            intent.putExtras(data);
            // TODO 跳转到文档详情
            startActivity(intent);
            finish();
        }
    }


    private volatile boolean isSnapshot = false;

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            isSnapshot = true;
            return true;
        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }
}
